const { createRedisClient } = require('../../util/redis')
const { RequestAreToFrequentErr } = require('../../response/code')
/**
 * 接口防刷中间件
 * @param {Object} options 配置选项
 * @param {number} options.windowMs 时间窗口（毫秒），默认60000ms（1分钟）
 * @param {number} options.max 最大请求数，默认60次
 * @param {string} options.prefix Redis键前缀，默认'rate_limit'
 */
const rateLimit = (options = {}) => {
  const { windowMs = 60000, max = 60, prefix = 'rate_limit' } = options

  return async (ctx, next) => {
    // 获取客户端IP地址
    const ip =
      ctx.request.ip ||
      ctx.request.headers['x-forwarded-for'] ||
      ctx.request.connection.remoteAddress ||
      ctx.request.socket.remoteAddress ||
      (ctx.request.connection.socket
        ? ctx.request.connection.socket.remoteAddress
        : null)

    // 如果无法获取IP，则直接放行
    if (!ip) {
      await next()
      return
    }

    // 构造Redis键
    const key = `${prefix}:${ip}`

    // 创建Redis客户端
    const redisClient = createRedisClient()

    try {
      // 连接Redis
      await redisClient.connect()

      // 获取当前IP在时间窗口内的请求数
      let current = await redisClient.get(key)

      if (current === null) {
        // 如果是第一次请求，设置键值和过期时间
        await redisClient.set(key, 1, { PX: windowMs })
        await redisClient.quit()
        await next()
        return
      }

      // 增加请求数
      current = parseInt(current)

      if (current >= max) {
        // 超过限制，返回错误
        await redisClient.quit()

        return ctx.app.emit('error', RequestAreToFrequentErr, ctx)
      }

      // 增加计数
      await redisClient.incr(key)
      await redisClient.quit()
      await next()
    } catch (err) {
      // Redis连接或操作失败时，直接放行请求
      try {
        await redisClient.quit()
      } catch (e) {
        // 忽略关闭连接时的错误
      }
      await next()
    }
  }
}

module.exports = {
  rateLimit,
}
